﻿using AngleSharp.Dom;

namespace GoodAdmin.System;

public class BaseService : IBaseService, ITransient
{
    private readonly ISysRoleService _sysRoleService;
    private readonly ISysOrgService _sysOrgService;
    private readonly IRelationService _relationService;
    private readonly IRedisCacheManager _redisCacheManager;

    public BaseService(ISysRoleService sysRoleService, ISysOrgService sysOrgService,
        IRelationService relationService, IRedisCacheManager redisCacheManager)
    {
        _sysRoleService = sysRoleService;
        _sysOrgService = sysOrgService;
        _relationService = relationService;
        _redisCacheManager = redisCacheManager;
    }
    /// <inheritdoc/>
    public async Task<List<ApiRole>> GetUserApiRoles()
    {
        //先从缓存获取，如果有数据，直接返回
        string key = CacheConst.ApiRole + UserManager.UserId;
        List<ApiRole> apiRoles = _redisCacheManager.Get<List<ApiRole>>(key);
        if (apiRoles != null) return apiRoles;

        apiRoles = new List<ApiRole>();
        //获取用户拥有角色
        var roleList = await _sysRoleService.GetUserRoleList(UserManager.UserId);
        if (roleList == null)
        {
            //没有权限的同样存储
            _redisCacheManager.Set(key, apiRoles);
            return apiRoles;
        }

        var orgList = await _sysOrgService.GetOrgList();
        var orgIdList = orgList.Select(o => o.Id).ToList();
        //超级管理员拥有所有数据范围权限
        if (roleList.Any(it => it.Code == RoleConst.SUPERADMIN))
        {
            apiRoles.Add(new ApiRole { RouteUrl = RoleConst.SUPERADMIN, OrgList = [], ScopeType= RoleConst.DATA_SCOPE_ALL });
            _redisCacheManager.Set(key, apiRoles);
            return apiRoles;
        }
        //获取角色资源列表
        var resourceRealtion = await _relationService.GetRelationListByObjectIdList(CategoryConst.RELATION_ROLE_RESOURCE, roleList.Select(r => r.Id).ToList());
        if (resourceRealtion.Count == 0)
        {
            _redisCacheManager.Set(key, apiRoles);
            return apiRoles;
        }

        var resourceOutputList = resourceRealtion.Select(it => it.ExtraJson.ToJsonEntity<List<ResourceInfo>>());
        var resourceList = resourceOutputList.SelectMany(it => it).Distinct().ToList();
        //根据路由进行分组
        var resourceGroup = resourceList.GroupBy(it => it.ApiRoute).ToList();
        //获取所有下级组织id列表
        var childIdList = await _sysOrgService.GetOrgChildrenIdList(UserManager.OrgId);
        //循环添加数据范围
        //it表示路由
        resourceGroup.ForEach(it =>
        {
            //转换为列表
            var apiResourceList = it.ToList();
            //如果接口不用设置数据范围，那么就添加路由后直接返回
            if (apiResourceList.Any(item => !item.IsDataScope))
            {
                apiRoles.Add(new ApiRole { RouteUrl = it.Key, OrgList = [], ScopeType = "" });
                return;
            }
            
            HashSet<long> dataScope = new();

            //先为数据范围类型设置默认值
            string scopeType = RoleConst.DATA_SCOPE_SELF;

           
            //先判断是否有数据范围为全部的
            if (apiResourceList.Any(item => item.DataScopeType == RoleConst.DATA_SCOPE_ALL))
            {
                scopeType = RoleConst.DATA_SCOPE_ALL;
            }
            //如果没有，那么则循环处理每个数据范围
            else
            {
                int degree = GetScopeTypeDegree(scopeType);
                apiResourceList.ForEach(async item =>
                {                   
                    if (item.DataScopeType == RoleConst.DATA_SCOPE_SELF)//仅自己
                    {
                        return;
                    }
                    else if (item.DataScopeType == RoleConst.DATA_SCOPE_SELF)//仅本级组织
                    {
                        dataScope.Add(UserManager.OrgId);
                    }
                    else if (item.DataScopeType == RoleConst.DATA_SCOPE_ORG_CHILD)//本级以及下级组织
                    {                        
                        dataScope.AddRange(childIdList);
                    }
                    else if (item.DataScopeType == RoleConst.DATA_SCOPE_APPOINT_ORG_CHILD)//指定组织以及下级组织
                    {
                        var orgIds = await _sysOrgService.GetOrgChildrenIdList(item.DefineScopeOrgList);
                        dataScope.AddRange(orgIds);
                    }
                    else if (item.DataScopeType == RoleConst.DATA_SCOPE_DEFINE)//自定义组织
                    {
                        dataScope.AddRange(item.DefineScopeOrgList);
                    }

                    //判断数据范围级别，如果比当前级别大，那么就设置为大的那个
                    int curDegree = GetScopeTypeDegree(item.DataScopeType);
                    if (curDegree > degree)
                    {
                        scopeType = item.DataScopeType;
                    }
                });
            }
            apiRoles.Add(new ApiRole { RouteUrl = it.Key, OrgList = [.. dataScope], ScopeType = scopeType });
        });

        //根据userid使用string方式存储每个用户的数据范围
        _redisCacheManager.Set(key, apiRoles);
        return apiRoles;
    }

    /// <summary>
    /// 获取公共权限API接口列表
    /// 公共权限数据范围仅为[仅本人]
    /// </summary>
    /// <returns></returns>
    public async Task<List<ApiRole>> GetCommonApiRole()
    {
        string key = CacheConst.CommonRoleApi;
        List<ApiRole> apiRoles = _redisCacheManager.Get<List<ApiRole>>(key);
        if (apiRoles == null)
        {
            apiRoles = [];
            var commonRole = await _sysRoleService.GetCommonRole();
            //获取角色资源列表
            var resourceRealtion = await _relationService.GetRelationListByObjectId(CategoryConst.RELATION_ROLE_RESOURCE, commonRole.Id);
            if (resourceRealtion.Count == 0)
            {
                _redisCacheManager.Set(key, apiRoles);
                return apiRoles;
            }
            var resources = resourceRealtion[0].ExtraJson.ToJsonEntity<List<ResourceInfo>>();
            resources.ForEach(item =>
            {
                string scopeType;
                if (!item.IsDataScope)
                {
                    scopeType = "";
                }
                else
                {
                    scopeType = item.DataScopeType;
                }
                apiRoles.Add(new ApiRole { RouteUrl = item.ApiRoute, OrgList = [], ScopeType = scopeType });
            });
            _redisCacheManager.Set(key, apiRoles);
        }
        return apiRoles;
    }
    /// <inheritdoc/>
    public async Task<ApiRole> GetUserApiRoleByRequest()
    {
        //路由名称
        var routeName = App.HttpContext.Request.Path.Value;
        //获取用户数据范围
        var apiRoles = await GetUserApiRoles();
        var dataScope = apiRoles.Where(d => d.RouteUrl == RoleConst.SUPERADMIN).FirstOrDefault() ??
            apiRoles.Where(d => d.RouteUrl == routeName).FirstOrDefault();
        return dataScope;
    }
    public async Task<ApiRole> GetCommonApiRoleByRequest()
    {
        //路由名称
        var routeName = App.HttpContext.Request.Path.Value;
        //获取用户数据范围
        var apiRoles = await GetCommonApiRole();
        var dataScope = apiRoles.Where(d => d.RouteUrl == routeName).FirstOrDefault();
        return dataScope;
    }
    /// <inheritdoc/>
    public async Task<List<long>> GetUserApiRoleOrgIdByRequest()
    {
        var apiRole = await GetUserApiRoleByRequest();
        var orgIdList = new List<long>();
        if (apiRole != null)
        {
            if(apiRole.ScopeType == RoleConst.DATA_SCOPE_ALL)
            {
                var orgList = await _sysOrgService.GetOrgList();
                orgIdList = orgList.Select(o => o.Id).ToList();
            }
            else
            {
                orgIdList.AddRange(apiRole.OrgList);
            }            
        }
        return orgIdList;
    }

    /// <inheritdoc/>
    public async Task CheckDataScope(long OrgId, long UserId = 0)
    {
        await CheckDataScope(new List<long> { OrgId },UserId);
    }

    /// <inheritdoc/>
    public async Task CheckDataScope(List<long> OrgIdList, long UserId = 0)
    {
        if (UserManager.SuperAdmin) return;
        var dataScope = await GetUserApiRoleByRequest();
        if (dataScope.ScopeType == RoleConst.DATA_SCOPE_SELF)
        {
            //如果没有资源数据范围权限，那么判断是否是当前操作人自己
            if (UserId > 0 && UserId != UserManager.UserId)
                throw Oops.Bah(OrgErrorCode.O007);
        }
        else if (!dataScope.OrgList.ContainsAll(OrgIdList))
        {
            throw Oops.Bah(OrgErrorCode.O007);
        }
    }

    /// <summary>
    /// 设置数据范围级别
    /// </summary>
    /// <param name="ScopeType"></param>
    /// <returns></returns>
    private int GetScopeTypeDegree(string ScopeType)
    {
        Dictionary<string, int> scopeDegreeDic = new Dictionary<string, int>()
        {
            { RoleConst.DATA_SCOPE_ALL,9 },
            { RoleConst.DATA_SCOPE_APPOINT_ORG_CHILD,5},
            { RoleConst.DATA_SCOPE_ORG_CHILD,3},
            { RoleConst.DATA_SCOPE_DEFINE,2},
            { RoleConst.DATA_SCOPE_OWNORG,1},
            { RoleConst.DATA_SCOPE_SELF,0},
        };
        return scopeDegreeDic[ScopeType];
    }
}
